In [144]:
import sys

sys.argv[0]


Out[144]:
'c:\\users\\epaekey\\appdata\\local\\programs\\python\\python36-32\\lib\\site-packages\\ipykernel_launcher.py'

In [145]:
sys.argv


Out[145]:
['c:\\users\\epaekey\\appdata\\local\\programs\\python\\python36-32\\lib\\site-packages\\ipykernel_launcher.py',
 '-f',
 'C:\\Users\\epaekey\\AppData\\Roaming\\jupyter\\runtime\\kernel-2610b135-3f29-4328-9418-29b6108d48bf.json']

In [146]:
type(7)


Out[146]:
int

In [147]:
type(4.5)


Out[147]:
float

In [148]:
print(12/4)
print(type(12/4))
type(12/4)


3.0
<class 'float'>
Out[148]:
float

In [149]:
print(12//4)
type(12//4) # floor division


3
Out[149]:
int

In [150]:
print(12%4)
type(12%4)


0
Out[150]:
int

In [151]:
2 ** 4


Out[151]:
16

In [152]:
# Using a var without assigning a value yields a NameError
width


---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-152-845b054717f0> in <module>()
      1 # Using a var without assigning a value yields a NameError
----> 2 width

NameError: name 'width' is not defined

In [ ]:
2 * 2.5 + 2

In [ ]:
#_ should be treated as read_only. 
# It can be assigned to, but then you won't have a magic variable anymore
_  # if need to access last thing that was returned

In [ ]:
3j + 5

In [ ]:
3J + 5

In [ ]:
type(3J) # j is the impaginary part of the complex number

In [ ]:
1.J

In [ ]:
# Remove issues with quote escaping
print(r'whoa\\yay.com')

In [ ]:
#Otherwise leaving it out means you consider backslash an escape character
print('whoa\\yay.com')

In [ ]:
'''who
oo
oo'''

In [ ]:
# Remove end of line characters by prefacing with 1 backslash in a multiline comment
print("""\
Usage: thingy [OPTIONS]
     -h                        Display this usage message
     -H hostname               Hostname to connect to
""")

In [ ]:
'ho' * 3 + ' merry xmas'

In [ ]:
# 2 adjacent string literals are concatenated when they are interpreted
'py'        'thon'

In [ ]:
prefix = 'py'
prefix 'thon'

In [ ]:
prefix = 'py'
prefix + 'thon'

In [ ]:
# Can put long strings in a row
(
 'There are lots '
 'of strings '
 'in a row'
)

In [ ]:
# Indexing: 1 char at an index
'python'[0]

In [ ]:
'python'[-1]

In [ ]:
# Slicing: Multiple chars at specified indices

In [ ]:
'python'[1:3] 
# index includes char at 1st index, includes all chars up to and excluding 
# last index

In [ ]:
'python'[:3] + 'python'[3:]

In [ ]:
'''
 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
 0   1   2   3   4   5   6
-6  -5  -4  -3  -2  -1
'''

In [ ]:
'python'[50]

In [ ]:
# Handles gracefully
'python'[:50]

In [ ]:
'python'[0] = 'a' # Strings are immutable

In [ ]:
newword = 'python'[:2] + 'k' + 'python'[3:]
newword

In [ ]:
# Lists, dictionaries etc are COMPOUND data types. 
# Lists can have items of different types.
# Slicing creates a shallow copy of the list

In [ ]:
nummys = [[1],[2],[3],[4],[5]]
nummys[:]

In [ ]:
nummys[3] = 1000
nummys

In [ ]:
nummys.append(50)
nummys

In [ ]:
nummys[2:] = [] # assigning to a slice updates the original list
nummys

In [ ]:
nummys[:] = []
nummys

In [ ]:
nummys = [[1,2],[5,6]]
nummys[0][1]

In [ ]:
# multiple assignment, unpacks values from list into variables
# otherwise you get a value error
# rhs of expression is evaluated first, left to right
a, b = nummys 
b

In [ ]:
while 0: # 0 is false, any other number is True
    print('yay!')
    if 1==1:
        break

In [ ]:
while 0.1:
    print('yay!')
    if 1==1:
        break

In [ ]:
# any value that is has length > 0 is true, else it's false
if []:
    print('yay')

In [ ]:
if [0]:
    print('yay')

In [ ]:
# print function handles multiple args, floating points, and strings differently
print([[5.]])

In [ ]:
i = 5
print('its', i) #puts a space for you

In [154]:
# for statements: iterates over items of any sequence in the order they appear.
# using a slice copies the array for you
words = ['pauline', 'is', 'cool']

for w in words[:]:
    words.insert(0, len(w))
print(words)


[4, 2, 7, 'pauline', 'is', 'cool']

In [158]:
# range generates arithmetic progressions
list(range(8))


Out[158]:
[0, 1, 2, 3, 4, 5, 6, 7]

In [159]:
type(range(8))


Out[159]:
range

In [161]:
list(range(2,8))


Out[161]:
[2, 3, 4, 5, 6, 7]

In [163]:
list(range(2,8,-2))


Out[163]:
[]

In [164]:
# its better to use enumerate instead of range(len(w))
for index, value in enumerate([1,2,3]):
    print(index, value)


0 1
1 2
2 3

In [165]:
# The range object behaves as a list, but its just an object that returns successive items of the 
# right sequence when you iterate over it.
# By not making the list right away, it saves space.

# the range object is an 'iterable'.
# It's something that can be a target for funcions/constructs that expect something from which they can get 
# successive items until the end.

#list() creates lists from iterators
for a in list(range([1,2,3])):
    print(a)


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-165-d88a92b2af98> in <module>()
      7 # successive items until the end.
      8 
----> 9 for a in list(range([1,2,3])):
     10     print(a)

TypeError: 'list' object cannot be interpreted as an integer

In [168]:
words = ['one', 'two', 'three']
for i, w1 in enumerate(words):
    for j, w2 in enumerate(words):
        if i == j:
            print(i, 'equals!!')
            #break
    else:
        print(j, 'sheeeeit')


0 equals!!
2 sheeeeit
1 equals!!
2 sheeeeit
2 equals!!
2 sheeeeit

In [169]:
for a in range(8):
    if a % 2 == 0:
        print('whoa')
else:
    print('doneskis')


whoa
whoa
whoa
whoa
doneskis

In [174]:
for i in range(6):
    if i % 2 == 0:
        print(i, 'whoa')
    elif i == 5:
        break
else:
    print('doneskis') #if a break statement is executed, else block won't be executed.


0 whoa
2 whoa
4 whoa

In [175]:
for i in range(5):
    if i % 2 == 0:
        continue
    print(i)


1
3

In [177]:
# use pass for method stubs so they can compile
if 1==1:
    pass

In [179]:
def new_func():
    '''
    docstring
    '''
    return 2*2

new_func()


Out[179]:
4

In [189]:
### function definitions create a new symbol table for local vars.
### variable references are first checked in this symbol table, then the 
### symbol table of the outer scope, and so on until its global, then in the table of built-in names.
# globals can't be directly assigned a value in a function.

a = 2
def f():
    #print(a)
    a = 7
    print(a)
f()
print(a)


7
2

In [195]:
# args are passed via call by value. The value is the reference of the object, not the actual object, added to symbol table

def change_list(lst):
    lst.append(4)
    
my_list = [1,2,3]

change_list(my_list[:]) #shallow copy
print(my_list)
change_list(my_list)
print(my_list)


[1, 2, 3]
[1, 2, 3, 4]

In [203]:
# functions return values, procedures do not (except in python it returns None, so I guess it is a function)
# methods are functions that belong to an object - it's a function enclosed within an object
# can have default values

def is_this_ok(answer='Yes'):
    if answer=='No':
        raise ValueError('EVERYTHING IS NOT OK')
    return answer

print(is_this_ok())
print(is_this_ok('No'))


Yes
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-203-bde4e3808b62> in <module>()
      9 
     10 print(is_this_ok())
---> 11 print(is_this_ok('No'))

<ipython-input-203-bde4e3808b62> in is_this_ok(answer)
      5 def is_this_ok(answer='Yes'):
      6     if answer=='No':
----> 7         raise ValueError('EVERYTHING IS NOT OK')
      8     return answer
      9 

ValueError: EVERYTHING IS NOT OK

In [206]:
global_thing = 9
global_thing = 7

def g(a=global_thing):
    print(a)
    
g(4)
global_thing = 8 #default variables are evaluated at the point of function definition in the defining scope
g()


4
7

In [207]:
#default value is evaluated only once.

def h(a=[]):
    a.append(1)
    return a

h()


Out[207]:
[1]

In [208]:
h()


Out[208]:
[1, 1]

In [209]:
def g(h=None):
    if h is None:
        h = []
    h.append(1)
    return h

print(g())
print(g())


[1]
[1]

In [212]:
# args, kwargs. a keyword argument is def(a=None), a positional argument is def(x,y)
# kwargs are optional arguments, args are required.
# kwargs have to follow positional arguments.

def f(lungs=2, hearts):
    print(lungs, hearts)


  File "<ipython-input-212-bb4e1bc619d6>", line 5
    def f(lungs=2, hearts):
         ^
SyntaxError: non-default argument follows default argument

In [218]:
def f(*arguments):
    print(arguments)

#numbers = [1,2,3]
f(1,2,3)


(1, 2, 3)

In [224]:
def g(**kwargs): # turns the keyword arguments into a dictionary
    return kwargs
    
my_dict = g(i=1, j=2)
print(my_dict['i'])
my_dict


1
Out[224]:
{'i': 1, 'j': 2}

In [225]:
# arbitrary arg lists
# * indicates a variatic argument, any args after this must be kwargs.
def h(*args, sep="/"):
    return sep.join(args)

h('1', '2', '3')


Out[225]:
'1/2/3'

In [227]:
# unpacking arg lists
# lists in a tuple, but need unpacking for a function that needs separate pos args.
args = [1,2,3]
list(range(*args))


Out[227]:
[1]

In [230]:
d = { 'volts':1, 'current': 2}

def converter(volts, current=3):
    print(volts, current)
    
converter(**d)


1 2

In [239]:
# lambda functions are small and anonymous. Used where you can use regular functions, if they have a single expression.

fired = lambda x: x + 5

fired(1)


Out[239]:
6

In [245]:
pairs = [(1, 'one'), (2, 'two'), (3, 'three')]
pairs.sort(key=lambda pair: pair[1]) #sort alphabetically on the 2nd index of the tuple

pairs


Out[245]:
[(1, 'one'), (3, 'three'), (2, 'two')]

In [261]:
def my_lambda(n):
    """Summary
    
    Describe calling conventions, side effects, etc. """
    return lambda x, y: x + y + n

my_lambda(1)(2, 3)


Out[261]:
6

In [262]:
print(my_lambda.__doc__) # get the docstring from the function attribute


Summary
    
    Describe calling conventions, side effects, etc. 

In [270]:
# Function annotations: optional metadata about types in user defined functions.

def f(ham: str, eggs: str = 'eggs') -> str:
    print('Annotations', f.__annotations__)
    print(args)
    return ham + ' ' + eggs

f('hhham')


Annotations {'ham': <class 'str'>, 'eggs': <class 'str'>, 'return': <class 'str'>}
[1, 2, 3]
Out[270]:
'hhham eggs'

PEP-0008 Style Guide

https://www.python.org/dev/peps/pep-0008/

  • CamelCase for classes, snake_case for functions and methods

Data Structures


In [293]:
# Add item
my_list = [1, 2, 3, 4, 5]
print(my_list)
my_list.append(6)
my_list


[1, 2, 3, 4, 5]
Out[293]:
[1, 2, 3, 4, 5, 6]

In [294]:
# Add elements from an iterable to the end of the list
my_list = [1, 2, 3, 4, 5]
print(my_list)
my_list.extend(range(10, 5, -2))
my_list


[1, 2, 3, 4, 5]
Out[294]:
[1, 2, 3, 4, 5, 10, 8, 6]

In [299]:
# Insert at a particular index
my_list = [1, 2, 3, 4, 5]
print(my_list)
my_list.insert(-1, -1)
my_list.insert(0, -1)
my_list


[1, 2, 3, 4, 5]
Out[299]:
[-1, 1, 2, 3, 4, -1, 5]

In [301]:
my_list = [1, 2, 3, 4, 5]
print(my_list)
my_list.remove(1) # error if doesn't exist
my_list


[1, 2, 3, 4, 5]
Out[301]:
[2, 3, 4, 5]

In [309]:
my_list = [1, 2, 3, 4, 5]
print(my_list)
my_list.pop() # pops last value off the stack
print(my_list)
my_list.pop(0) # pops first value off the stack if index specified
print(my_list)


[1, 2, 3, 4, 5]
[1, 2, 3, 4]
[2, 3, 4]

In [317]:
my_list = [1, 2, 3, 4, 5]
print(my_list)
del my_list[:] # my_list is now empty, removes all elements
print(my_list)
#del my_list # completely removes the name reference as well
my_list = [1, 2, 3, 4, 5]
print(my_list)
my_list.clear()
my_list


[1, 2, 3, 4, 5]
[]
[1, 2, 3, 4, 5]
Out[317]:
[]

In [322]:
my_list = [1, 2, 3, 4, 5]
index = my_list.index(4)
print(index)
index = my_list.index(3, 2, 4) # find an elem within a substring
print(index)


3
2

In [323]:
my_list = [1, 2, 3, 4, 5, 5]
my_list.count(5)


Out[323]:
2

In [327]:
my_list = [5, 1, 2, 3, 4]
print(my_list)
my_list.sort()
print(my_list)
my_list.sort(reverse=True)
print(my_list)


[5, 1, 2, 3, 4]
[1, 2, 3, 4, 5]
[5, 4, 3, 2, 1]

In [331]:
my_list = [(5, 1),(2, 3), (4, 6)]
my_list.sort() # looks at the first elem
print(my_list)

my_list.sort(reverse=True)
print(my_list)

my_list.sort(key=lambda x: x[1], reverse=True) #sorts in reverse based on the 2nd elem
print(my_list)


[(2, 3), (4, 6), (5, 1)]
[(5, 1), (4, 6), (2, 3)]
[(4, 6), (2, 3), (5, 1)]

In [332]:
my_list = [1, 2, 3, 4, 5]
my_list += my_list.copy() #same as my_list[:]
my_list


Out[332]:
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5]

In [342]:
# Turn a list into a stack - only use pop and append. This is efficiently implemented in python lists.
lst = []
lst.append(1)
lst.append(2)
print(lst)
lst.pop()
lst
print(lst)
lst


[1, 2]
[1]
Out[342]:
[1]

In [343]:
# Lists don't make a good FIFO queue - it's not very efficient.
_


Out[343]:
[1]

In [ ]: